<?php

namespace Symfony\Components\Console\Input;

/*
 * This file is part of the symfony framework.
 *
 * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

/**
 * StringInput represents an input provided as a string.
 *
 * Usage:
 *
 *     $input = new StringInput('foo --bar="foobar"');
 *
 * @package    symfony
 * @subpackage console
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
 */
class StringInput extends ArgvInput
{
  const REGEX_STRING = '([^ ]+?)(?: |(?<!\\\\)"|(?<!\\\\)\'|$)';
  const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';

  /**
   * Constructor.
   *
   * @param string     $input An array of parameters from the CLI (in the argv format)
   * @param InputDefinition $definition A InputDefinition instance
   */
  public function __construct($input, InputDefinition $definition = null)
  {
    parent::__construct(array(), $definition);

    $this->tokens = $this->tokenize($input);
  }

  protected function tokenize($input)
  {
    $input = preg_replace('/(\r\n|\r|\n|\t)/', ' ', $input);

    $tokens = array();
    $length = strlen($input);
    $cursor = 0;
    while ($cursor < $length)
    {
      if (preg_match('/\s+/A', $input, $match, null, $cursor))
      {
      }
      elseif (preg_match('/([^="\' ]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor))
      {
        $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
      }
      elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor))
      {
        $tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
      }
      elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor))
      {
        $tokens[] = stripcslashes($match[1]);
      }
      else
      {
        // should never happen
        // @codeCoverageIgnoreStart
        throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
        // @codeCoverageIgnoreEnd
      }

      $cursor += strlen($match[0]);
    }

    return $tokens;
  }
}
